#include <stdio.h>
#include <stdlib.h> 
#include <sys/time.h>
#include <math.h>
#include <GLUT/glut.h> 

#define kWindowWidth      800 
#define kWindowHeight     800
#define animateSteps      100
#define OUTERLOOP         (0x100000)
#define INNERLOOP         (8)

#define PI 3.14159265

float a,b,c,d,x,y;
float a0, b0, c0, d0;
float deltaA, deltaB, deltaC, deltaD;

float random(float min, float max)
{
  return (float)rand() / (float)RAND_MAX * (float)(max-min) + (float)min;
}

void setRandom()
{
  a = random(0, PI);
  b = random(0, PI);
  c = random(0, PI);
  d = random(0, PI);
}

void keyboard(unsigned char key, int x, int y)
{
  if (key == 27)
    glutPositionWindow(100, 100);  
}

void display()
{
  static timeval t0 = {0};
  timeval t1;
  gettimeofday(&t1, NULL);
  if (t0.tv_sec != 0)
  {
    printf("%f\n", (double)(t1.tv_sec-t0.tv_sec)+(double)(t1.tv_usec-t0.tv_usec)/1000000);
  }
  t0 = t1;
  
  static unsigned int times = 0;
  
  if (times == animateSteps)
  {
    times = 0;
  }

  if (times == 0)
  {
    a0 = a;
    b0 = b;
    c0 = c;
    d0 = d;

    setRandom();

    deltaA = (a - a0)/animateSteps;
    deltaB = (b - b0)/animateSteps;
    deltaC = (c - c0)/animateSteps;
    deltaD = (d - d0)/animateSteps;

    a = a0;
    b = b0;
    c = c0;
    d = d0;
  }

  glClear(GL_COLOR_BUFFER_BIT);
  glBegin(GL_POINTS);
  
  for (int i=0; i<OUTERLOOP; i++)
  {
    x = random(-2, 2);
    y = random(-2, 2);

    for(int j=0; j<INNERLOOP; j++)
    {
      float xn = sinf(a*y) - cosf(b*x);
      float yn = sinf(c*x) - cosf(d*y);

      x = xn;
      y = yn;

      glVertex2f(x*0.5f, y*0.5f);
    }
  }

  glEnd();

  glutSwapBuffers();

  a += deltaA;
  b += deltaB;
  c += deltaC;
  d += deltaD;
  
  times++;
} 

void graphicsSetup(void)
{
  float subColor = 1.0f/255;
  
  // clear and set color
  glClearColor(1, 1, 1, 1);
  glClear(GL_COLOR_BUFFER_BIT);
  glColor4f(subColor, subColor, subColor, 0);

  // setup alpha
  glEnable(GL_BLEND);
  glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
  glBlendFunc(GL_ONE, GL_ONE);

  // setup point render params
  // default point params work well!
  // glPointSize(1);

  // load identity
  glLoadIdentity();
}

int main(int argc, char** argv) 
{
  //setup initial values
  srand( time(NULL) );
  
  glutInit(&argc, argv); 
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); 
  glutInitWindowSize(kWindowWidth, kWindowHeight); 
  glutInitWindowPosition(100, 100); 
  glutCreateWindow("Peter De Jong");

  //glutFullScreen();
  
  graphicsSetup();

  setRandom();

  glutKeyboardFunc(keyboard);

  glutDisplayFunc(display);

  glutIdleFunc(display);

  glutMainLoop();

  return 0;
}
